package cn.cdzdjd.util;

import java.util.Base64;
import java.util.Date;
import java.util.UUID;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.DefaultClaims;

public class TokenUtil {
	// 密钥明文
	private static final String SECRET_CLEARTEXT = "LeoJiangNOMONEY";
	// 过期时间默认为30天后过期
	private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30L;
	//private static final long EXPIRATION_TIME = 10000L;
	/**
	 * @description 以Base64编码获取一个AES算法密钥
	 * @author
	 * @date 16:22 2022/10/14
	 * @return javax.crypto.SecretKey
	 **/
	public static SecretKey getSecretKey() {
		// 以Base64编码获取到明文密钥的字节 以该数组生成一个AES算法的的密钥
		return new SecretKeySpec(Base64.getDecoder().decode(SECRET_CLEARTEXT), "AES");
	}

	/***
	 * @description 获取一个无 - 作为token的唯一ID
	 * @author
	 * @date 16:07 2022/10/14
	 * @return java.lang.String
	 **/
	public static String getUUID() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}

	/***
	 * @description 以默认的过期时间构造token
	 * @author
	 * @date 16:07 2022/10/14
	 * @param str 存放在token里的信息
	 * @return java.lang.String
	 **/
	public static String getToken(String str) {
		return getJwtBuilder(str).compact();
	}

	/***
	 * @description 以指定的过期时间构造token
	 * @author
	 * @date 16:07 2022/10/14
	 * @param str   存放在token里的信息
	 * @param mills 指定多少毫秒后过期
	 * @return java.lang.String
	 **/
	public static String getToken(String str, long mills) {
		return getJwtBuilder(str, mills).compact();
	}

	/**
	 * @description 获取一个JWT的构造器
	 * @author
	 * @date 16:09 2022/10/14
	 * @param str
	 * @return io.jsonwebtoken.JwtBuilder
	 **/
	public static JwtBuilder getJwtBuilder(String str) {
		if (str == null) {
			throw new RuntimeException("实体数据为空");
		}
		// 获取到AES算法的密钥
		long nowMills = System.currentTimeMillis();
		DefaultClaims defaultClaims = new DefaultClaims();

		defaultClaims.put("userId", str);
		return Jwts.builder().setId(getUUID()) // 唯一的ID
				.setSubject("token") // 数据
				.setIssuer("LeoJiang") // 签发者
				.setClaims(defaultClaims) // 数据
				.setIssuedAt(new Date(nowMills)) // 签发时间设置为当前
				.signWith(SignatureAlgorithm.HS256, getSecretKey()) // 使用HS256对称加密算法签名, 第二个参数为秘钥
				.setExpiration(new Date(nowMills + EXPIRATION_TIME));// 设置为超时时间
	}

	/***
	 * @description 获取一个token的构造器
	 * @author
	 * @date 15:51 2022/10/14
	 * @param str   数据
	 * @param mills 过期时间
	 * @return io.jsonwebtoken.JwtBuilder
	 **/
	public static JwtBuilder getJwtBuilder(String str, long mills) {
		if (str == null)
			throw new RuntimeException("实体数据为空");
		// 获取到AES算法的密钥
		long nowMills = System.currentTimeMillis();
		DefaultClaims defaultClaims = new DefaultClaims();
		defaultClaims.put("userId", str);
		return Jwts.builder()// 一个构造器 下面为必要属性的设置
				.setId(getUUID()) // 唯一的ID
				.setSubject("token") // 主题为token
				.setIssuer("LeoJiang") // 签发者
				.setClaims(defaultClaims) // 数据存放
				.setIssuedAt(new Date(nowMills)) // 签发时间设置为当前
				.signWith(SignatureAlgorithm.HS256, getSecretKey()) // 使用HS256对称加密算法签名, 第二个参数为秘钥
				.setExpiration(new Date(nowMills + mills));// 设置过期时间
	}

	/**
	 * @description 从给定的token中获取msg信息
	 * @author
	 * @date 16:09 2022/10/14
	 * @param token token
	 * @return java.lang.String
	 **/
	public static String getUserId(String token) throws UnsupportedJwtException, // 不支持的格式异常
			MalformedJwtException, // 平台jwt异常
			SignatureException, // 签名异常
			ExpiredJwtException, // 超时异常
			IllegalArgumentException { // 非法参数异常
		return Jwts.parser()// token的语法分析器
				.setSigningKey(getSecretKey())// 设置签名验证所用的密钥
				.parseClaimsJws(token)// 处理token
				.getBody()// 获取存入的token里的所有信息
				.get("userId").toString();// 获取claims里面存放的msg数据
	}

	/**
	 * @description 判断token是否过期
	 * @author
	 * @date 16:09 2022/10/14
	 * @param token token
	 * @return java.lang.String
	 **/
	public static boolean expire(String token) {
		return Jwts.parser()// token的语法分析器
				.setSigningKey(getSecretKey())// 设置签名验证所用的密钥
				.parseClaimsJws(token)// 处理token
				.getBody().getExpiration().after(new Date());
	}

	public static void main(String[] args) {
		//1793703549918760987
		String token = TokenUtil.getToken("1793703549918760987",10000);
		System.out.println(token);
		System.out.println("msg: " + TokenUtil.getUserId(token));
		System.out.println(TokenUtil.expire(token));
	}
}
